package com.ck.company.service.impl;

import com.ck.common.service.OperationLogService;
import com.ck.company.service.CpSceneService;
import com.ck.company.service.CpVideoService;
import com.ck.config.CustomProperties;
import com.ck.constant.*;
import com.ck.dao.VideoMapper;
import com.ck.exception.ServiceException;
import com.ck.model.common.OperationLog;
import com.ck.model.common.User;
import com.ck.model.common.Video;
import com.ck.model.common.page.PageInfo;
import com.ck.model.company.dto.CpVideoListDTO;
import com.ck.model.company.vo.CpProgramVideoListVO;
import com.ck.model.company.vo.CpVideoListVO;
import com.ck.util.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;

/**
 * 视频Service实现类
 *
 * @author dxy
 * @date 2018/7/3 14:07
 */
@Service("cpVideoService")
public class CpVideoServiceImpl implements CpVideoService {
	@Autowired
	private VideoMapper videoMapper;
	@Autowired
	private CustomProperties customProperties;
	@Autowired
	private OperationLogService operationLogService;
	@Autowired
	private CpSceneService cpSceneService;

	/**
	 * 保存视频
	 *
	 * @param videoFile MultipartFile
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Map<String, Object> saveVideo(MultipartFile videoFile, HttpServletRequest request) throws IOException, ServiceException {
		//获取登录用户的商家编码
		User loginUser = (User) request.getSession().getAttribute(RequestConstant.SESSION_KEY_USER);
		String companyCode = loginUser.getCompanyCode();
		//获取视频名称
		String originalFilename = videoFile.getOriginalFilename();
		String fileExtension = FilenameUtils.getExtension(originalFilename);
		//去掉扩展名的文件名
		String fileName = originalFilename.replaceAll("." + fileExtension, "");
		//校验文件名是否存在
		Video oldVideo = getVideoByName(companyCode, fileName);
		//文件存在
		if (oldVideo != null) {
			//校验文件名是否与库中的同商家的视频文件名重复，如果重复，自动命名文件名，命名规则（a.jpg,a(1).jpg,a(2).jpg）
			//查找类型"a(1)"类似的文件，mysql匹配类型为“a(%)%”
			Long count = countVideoByName(companyCode, fileName + "(%)");
			if (count != null) {
				fileName = fileName + "(" + (count + 1)+ ")";
			}
		}
		//将MultipartFile转化为指定文件名的File
		File file = FileUtils.multipartFileConvertFile(videoFile, fileName + "." + fileExtension);
		//将视频上传至华为云
		String url = HuaWeiCloudUtils.uploadFile2HuaweiCloud(file, companyCode + "/video/");
		//获取视频md5值
		String md5 = FileUtils.getFileMD5(file);
		//获取视频时长
		Long videoLongDuration = MultimediaUtils.readVideoLongDuration(file);
		//获取视频大小
		long length = file.length();

		//获取视频第一帧图片存储到华为云并将地址存储到数据库
        File zip = ResourceUtils.getFile(ProgramZipConstant.ZIP_FOLDER);
        String basePath = zip.getAbsolutePath();
        File thumbnailFile = VideoUtils.randomGrabberImageReturnFile(file.getAbsolutePath(),
                basePath, String.valueOf(System.currentTimeMillis()), VideoUtils.IMG_TYPE_JPG);
        String thumbnailUrl = HuaWeiCloudUtils.uploadFile2HuaweiCloud(thumbnailFile, companyCode + "/videoThumbnail/");
        //把MultipartFile转化为File,会在本地创建文件，用完file后，需要删除
		if (file.exists()) {
			file.delete();
		}
		if(thumbnailFile != null && thumbnailFile.exists()){
			thumbnailFile.delete();
        }
		Video video = new Video();
		video.setVideoName(fileName);
		video.setCompanyCode(companyCode);
		video.setDuration(videoLongDuration);
		video.setMd5(md5);
		video.setUrl(url);
		video.setSize(length);
		video.setVideoSuffix(fileExtension);
		video.setAddTime(System.currentTimeMillis());
		video.setThumbnailUrl(thumbnailUrl);
		videoMapper.insertVideo(video);
		//返回给前端使用
		Map<String, Object> videoMap = Maps.newHashMap();
		videoMap.put("url", url);
		videoMap.put("duration", videoLongDuration);
		videoMap.put("file", url);
		videoMap.put("md5", md5);
		videoMap.put("size", length);
		videoMap.put("videoName", fileName);
		videoMap.put("videoSuffix", fileExtension);
		videoMap.put("videoId", video.getVideoId());
		videoMap.put("thumbnailUrl", thumbnailUrl);
		//记录操作日志
		OperationLog operationLog = new OperationLog();
		operationLog.setCopmanyCode(companyCode);
		operationLog.setOperationContent("保存视频,视频ID为:" + video.getVideoId());
		operationLog.setOperationStatus(BusinessConstant.OPERATION_LONG_OPERATION_STATUS_SUCCESS);
		operationLog.setOperationTime(System.currentTimeMillis());
		operationLog.setOperationModule(ModuleConstant.MODULE_MATERIAL + "-" + ModuleConstant.MODULE_VIDEO);
		operationLog.setRealname(loginUser.getRealname());
		operationLog.setUserName(loginUser.getUserName());
		operationLog.setOperationIp(HttpUtils.getRemortIP(request));
		operationLogService.saveOperationLog(operationLog);
		return videoMap;
	}

	/**
	 * 重命名
	 *
	 * @param videoNewName 视频新名称
	 * @param videoId      视频ID
	 * @param request      HttpServletRequest
	 * @throws ServiceException
	 * @throws IOException
	 */
	@Override
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void renameVideo(String videoNewName, Long videoId, HttpServletRequest request) throws ServiceException, IOException {
		if (videoId == null) {
			throw new ServiceException("视屏ID为空，请联系管理员");
		}
		Video video = videoMapper.getVideoById(videoId);
		if (video == null) {
			throw new ServiceException("视频不存在，请联系管理员");
		}
		//文件临时存放目录
		String fileTempSaveDir = customProperties.getFileTempSaveDir();
		String separator = File.separator;
		if (!fileTempSaveDir.endsWith(separator)) {
			fileTempSaveDir = fileTempSaveDir + separator;
		}
		String url = video.getUrl();
		String oldVideoName = video.getVideoName();
		String filePath = fileTempSaveDir + oldVideoName;
		//文件绝对路径
		String fullPath = filePath + "." + video.getVideoSuffix();
		//下载源视频文件
		FileUtils.downloadFileFromURL(url, fullPath);
		//重命名后视频名称
		String fullVideoNewName = videoNewName + "." + video.getVideoSuffix();
		//重命名视频
		Path path = Paths.get(fullPath);
		Files.move(path, path.resolveSibling(fullVideoNewName));
		//将重命名的视频上传至华为云
		File newFile = new File(fileTempSaveDir + fullVideoNewName);
		User loginUser = (User) request.getSession().getAttribute(RequestConstant.SESSION_KEY_USER);
		String companyCode = loginUser.getCompanyCode();
		//重新new一个Video，只设置需要更新的参数
		Video newVideo = new Video();
		if (newFile.exists()) {
			url = HuaWeiCloudUtils.uploadFile2HuaweiCloud(newFile, companyCode + "/video/");
			newVideo.setUrl(url);
			//删除本地临时视频
			newFile.delete();
		}
		newVideo.setVideoName(videoNewName);
		newVideo.setVideoId(videoId);
		videoMapper.updateVideoById(newVideo);
		//记录操作日志
		OperationLog operationLog = new OperationLog();
		operationLog.setCopmanyCode(companyCode);
		operationLog.setOperationContent("重命名视频,视频ID为:" + videoId);
		operationLog.setOperationStatus(BusinessConstant.OPERATION_LONG_OPERATION_STATUS_SUCCESS);
		operationLog.setOperationTime(System.currentTimeMillis());
		operationLog.setOperationModule(ModuleConstant.MODULE_MATERIAL + "-" + ModuleConstant.MODULE_VIDEO);
		operationLog.setRealname(loginUser.getRealname());
		operationLog.setUserName(loginUser.getUserName());
		operationLog.setOperationIp(HttpUtils.getRemortIP(request));
		operationLogService.saveOperationLog(operationLog);
	}

	/**
	 * 视频列表
	 *
	 * @param companyCode 商家编码
	 * @param videoName   视频名称
	 * @param pageNum     当前页
	 * @param pageSize    每页显示条数
	 * @return List<CpVideoListVO>
	 */
	@Override
	@Transactional(readOnly = true, rollbackFor = Exception.class)
	public PageInfo<CpVideoListVO> listVideo(String companyCode, String videoName, Integer pageNum, Integer pageSize) {
		//设置默认值
		if (pageNum == null) {
			pageNum = PageConstant.DEFAULT_PAGE_NUM;
		}
		if (pageSize == null) {
			pageSize = PageConstant.DEFAULT_PAGE_SIZE;
		}
		PageHelper.startPage(pageNum, pageSize);
		Page<CpVideoListDTO> page = videoMapper.listVideo(companyCode, videoName);
		PageInfo<CpVideoListVO> pageInfo = new PageInfo<>();
		pageInfo.setPageNum(pageNum);
		pageInfo.setPageSize(pageSize);
		pageInfo.setTotal(page.getTotal());

		List<CpVideoListVO> voList = Lists.newArrayList();
		List<CpVideoListDTO> dtoList = page.getResult();
		DecimalFormat df = new DecimalFormat("#.00");
		for (CpVideoListDTO dto : dtoList) {
			CpVideoListVO vo = new CpVideoListVO();
			vo.setVideoId(dto.getVideoId());
			vo.setVideoName(dto.getVideoName());
			Long size = dto.getSize();
			if (size == null) {
				vo.setSize("");
			} else {
				double l = size / (1024.0 * 1024);
				vo.setSize(df.format(l));
			}
			if(null != dto.getAddTime()){
				vo.setAddTime(DateUtils.longTimeStampToStringDate(dto.getAddTime(), DateFormatConstant.LONG_DATE_FORMAT_STR));
			}
			voList.add(vo);
		}
		pageInfo.setList(voList);
		return pageInfo;
	}

	/**
	 * 通过视频ID删除视频
	 *
	 * @param videoId 视频ID
	 * @param request HttpServletRequest
	 * @throws ServiceException
	 * @throws IOException
	 */
	@Override
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void deleteVideoById(Long videoId, HttpServletRequest request) throws ServiceException, IOException {
		//如果已在节目中存在，不能删除视频
		Video video = videoMapper.getVideoById(videoId);
		if (video == null) {
			throw new ServiceException("视频信息不存在，请联系管理员");
		}
		User loginUser = (User) request.getSession().getAttribute(RequestConstant.SESSION_KEY_USER);
		String companyCode = loginUser.getCompanyCode();
		if (StringUtils.isBlank(companyCode)) {
			throw new ServiceException("公司编码不能为空，请联系管理员");
		}
		String url = video.getUrl();
		if (StringUtils.isNotBlank(url)) {
			//校验视频是否被使用，具体验证逻辑，请查看SQL语句
			Long count = cpSceneService.countNoDeleteProgram(url);
			if (count > 0) {
				throw new ServiceException("视频正在被使用，不能删除");
			}
			//删除华为云上对应的视频
			String fileKey = companyCode + "/video/" + video.getVideoName();
			HuaWeiCloudUtils.deleteHuaweiCloudObject(fileKey);
		}
		//删除数据库中的视频数据
		videoMapper.deleteVideoById(videoId);
		//记录操作日志
		OperationLog operationLog = new OperationLog();
		operationLog.setCopmanyCode(companyCode);
		operationLog.setOperationContent("删除视频,视频ID为:" + videoId);
		operationLog.setOperationStatus(BusinessConstant.OPERATION_LONG_OPERATION_STATUS_SUCCESS);
		operationLog.setOperationTime(System.currentTimeMillis());
		operationLog.setOperationModule(ModuleConstant.MODULE_MATERIAL + "-" + ModuleConstant.MODULE_VIDEO);
		operationLog.setRealname(loginUser.getRealname());
		operationLog.setUserName(loginUser.getUserName());
		operationLog.setOperationIp(HttpUtils.getRemortIP(request));
		operationLogService.saveOperationLog(operationLog);
	}

	/**
	 * 查询某商家视频列表
	 *
	 * @param companyCode 商家编码
	 * @param videoName   视频名称
	 * @param pageNum     当前页
	 * @param pageSize    每页条数
	 * @return Page<CpVideoListVO>
	 */
	@Override
	public Page<CpProgramVideoListVO> listProgramVideo(String companyCode, String videoName, Integer pageNum, Integer pageSize) {
		PageHelper.startPage(pageNum, pageSize);
		return videoMapper.listProgramVideo(companyCode, videoName);
	}

	/**
	 * 通过视频名称获取视频
	 *
	 * @param companyCode 商家编码
	 * @param videoName   视频名称
	 * @return Video
	 * @throws ServiceException
	 */
	@Override
	public Video getVideoByName(String companyCode, String videoName) throws ServiceException {
		if (StringUtils.isBlank(companyCode) || StringUtils.isBlank(videoName)) {
			throw new ServiceException("输入参数不能为空");
		}
		return videoMapper.getVideoByName(companyCode, videoName);
	}

	/**
	 * 获取视频名称类似的条数
	 * @param companyCode 商家编码
	 * @param videoName 视频名称
	 * @return Long(视频条数)
	 * @throws ServiceException
	 */
	@Override
	public Long countVideoByName(String companyCode, String videoName) throws ServiceException {
		if (StringUtils.isBlank(companyCode) || StringUtils.isBlank(videoName)) {
			throw new ServiceException("输入参数不能为空");
		}
		return videoMapper.countVideoByName(companyCode, videoName);
	}

}
